package com.xiashitech.apiservice.job.listener;

import cn.hutool.core.stream.StreamUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;

import com.xiashitech.apiservice.Constants.ErrorCode;
import com.xiashitech.apiservice.config.AuthConfig;
import com.xiashitech.apiservice.dao.AgentNodeMapper;
import com.xiashitech.apiservice.dao.model.AgentNode;
import com.xiashitech.apiservice.dao.model.PushHistory;
import com.xiashitech.apiservice.dto.AgentIdentityDTO;
import com.xiashitech.apiservice.grpc.IncrementalCacheService;
import com.xiashitech.apiservice.service.IAgentConfigService;
import com.xiashitech.apiservice.service.IAgentNodeService;
import com.xiashitech.apiservice.service.IPushHistroyService;
import com.xiashitech.apiservice.service.IPushService;
import com.xiashitech.interfaces.agent.dto.AgentConfigDTO;
import com.xiashitech.interfaces.apiservice.dto.base.Response;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Component
@Service
@RequiredArgsConstructor(onConstructor = @_(@Autowired))
public class RabbitMqListener {
    private final AuthConfig authConfig;
    private final IPushService pushService;
    private final IPushHistroyService pushHistroyService;
    private final IncrementalCacheService incrementalCacheService;
    private final IAgentNodeService agentNodeService;
    private final IAgentConfigService agentConfigService;
    public final static String systemId = "systemId";
    public final int pageSize = 1000;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    private Logger logger = LoggerFactory.getLogger(RabbitMqListener.class);

    @RabbitListener(queues = "damQueue", concurrency = "10")
    @Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 100000, multiplier = 1.5))
    public void processC(String obj) throws Exception {
        System.out.println("receiver:damQueue:" + obj);
        // int pageSize = 1000;
        try {
            new Thread(() -> {
                System.out.println("start:damQueue thread");
                JSONObject changeObj = new JSONObject();
                String systemId = JSONUtil.parseObj(obj).get("systemId").toString();
                AgentNode agentNode = new AgentNode();
                agentNode.setSystemId(systemId);
                List<AgentNode> agentListAll = agentNodeService.selectAgentNode(agentNode);
                System.out.println("start:damQueue select agentNode: " + agentNode.getSystemId() + ", size: " + (agentListAll== null?"NULL":agentListAll.size()));
                // 这个也没用？注释掉？ TODO
                String finalSystemId = systemId;
                AgentConfigDTO agentConfigDTO = agentConfigService.syncConfig();
                changeObj.putOpt("systemId", JSONUtil.parseObj(obj).get("systemId").toString());
                String pushkey = JSONUtil.parseObj(obj).get("pushKey").toString();
                System.out.println("start:damQueue pushkey: " + pushkey);
                if ("permissionChange".equals(pushkey)) {
                    String beforeObj = JSONUtil.parseObj(obj).get("old").toString();
                    String afterObj = JSONUtil.parseObj(obj).get("new").toString();
                    JSONObject damObj = JSONUtil.parseObj(obj);
                    //String systemId = String.valueOf(damObj.get("system_id"));

                    // authDTO.setIamBaseUrl(authConfig.getIamBaseUrl());
                    JSONArray beforeArray = JSONUtil.parseArray(beforeObj);
                    JSONArray afterArray = JSONUtil.parseArray(afterObj);

                    System.out.println("start:damQueue pushkey: " + pushkey + ", afterArray size: " + (afterArray==null?"NULL":afterArray.size()) + ", beforeArray size: " + (beforeArray==null?"NULL":beforeArray.size()));
                    JSONObject diffObj = pushService.damDiff(beforeArray, afterArray, systemId, 1, pageSize);
                    int curPage = 1;
                    int pageTotal = diffObj.getInt("pageTotal");
                    diffObj.putOpt("pushId", systemId);
                    diffObj.putOpt("pushKey", pushkey);
                    diffObj.putOpt("page", curPage);
                    diffObj.putOpt("pageSize", pageSize);
                    diffObj.putOpt("change", diffObj.get("change"));
                    diffObj.putOpt("pageTotal", pageTotal);
                    System.out.println("start:damQueue diffObj pageTotal: " + pageTotal + ", diffObj String: " + diffObj);
                    pushService.pushToNode(systemId, agentListAll, diffObj);
                    while (curPage < diffObj.getInt("pageTotal")) {
                        curPage++;
                        diffObj = pushService.damDiff(new JSONArray(), diffObj.getJSONArray("nextArr"), systemId,curPage, pageSize);
                        diffObj.putOpt("systemId", systemId);
                        diffObj.putOpt("pushKey", pushkey);
                        diffObj.putOpt("page", curPage);
                        diffObj.putOpt("pageSize", pageSize);
                        diffObj.putOpt("change", diffObj.get("change"));
                        diffObj.putOpt("pageTotal", pageTotal);
                        System.out.println("start:damQueue now is page push curPage: " + curPage);
                        pushService.pushToNode(systemId, agentListAll, diffObj);
                    }
                } else if ("groupUserChange".equals(pushkey)) {
                    systemId = JSONUtil.parseObj(obj).get("systemId").toString();
                    changeObj.putOpt("pushKey", pushkey);
                    changeObj.putOpt("systemId", systemId);
                    JSONObject userChangeObj = JSONUtil.parseObj(JSONUtil.parseObj(obj).get("change")).getJSONObject("userChange");
                    String groupId = userChangeObj.getStr("groupId");
                    String url = StrUtil.format(authConfig.getApiUrlForGetDamInfoByGroupId(), groupId);
                    String json = HttpUtil.get(url);
                    if (JSONUtil.isTypeJSONArray(JSONUtil.parseObj(json).get("data").toString())) {
                        JSONArray groupUserChangeDamArr = JSONUtil.parseObj(json).getJSONArray("data");
                        if (groupUserChangeDamArr != null) {
                            JSONObject diffObj = pushService.getGroupUserChangeDam(groupUserChangeDamArr, systemId,userChangeObj);
                            int curPage = 1;
                            diffObj.putOpt("pushKey", pushkey);
                            diffObj.putOpt("systemId", systemId);
                            diffObj.putOpt("page", curPage);
                            diffObj.putOpt("pageSize", pageSize);
                            //  diffObj.putOpt("change", diffObj.get("pushArr"));
                            diffObj.putOpt("pageTotal", diffObj.get("pageTotal"));
                            pushService.pushToNode(systemId, agentListAll, diffObj);

                        }
                    }

                }
            }).start();

        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("receive damQueue error" + obj);
        }
    }

    @RabbitListener(queues = "desensitizationQueue", concurrency = "10")
    @Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 2000, multiplier = 1.5))
    public void topics(String obj) throws Exception {
        System.out.println("receiver:authQueue:" + obj);
        try {
            String systemId = JSONUtil.parseObj(obj).get("systemId").toString();
            JSONObject changeObj = new JSONObject();
            changeObj.putOpt("systemId", systemId);
            String pushkey = JSONUtil.parseObj(obj).get("pushKey").toString();
            System.out.println("start:authQueue pushkey:" + pushkey);
            if ("desensitizationChange".equals(pushkey)) {
                changeObj.putOpt("change", JSONUtil.parseObj(obj).get("change"));
                changeObj.putOpt("pushKey", pushkey);

                AgentNode agentNode = new AgentNode();
                agentNode.setSystemId(systemId);
                List<AgentNode> agentListAll = agentNodeService.selectAgentNode(agentNode);
                System.out.println("start:authQueue agentListAll systemId:" + systemId + ", size: " + (agentListAll==null?"NULL":agentListAll.size()));
                if(agentListAll==null && agentListAll.size()>0) {
                    agentListAll.stream().forEach(node->System.out.println("agentListAll: " + node.getSystemId()+", " + node.getServiceId() + ", " + node.getSerialId()));
                }
                List<AgentIdentityDTO> currentHostAgentList = incrementalCacheService.getAgentIds(systemId);
                System.out.println("start:authQueue currentHostAgentList systemId:" + systemId + ", size: " + (currentHostAgentList==null?"NULL":currentHostAgentList.size()));
                if(currentHostAgentList==null && currentHostAgentList.size()>0) {
                    currentHostAgentList.stream().forEach(node->System.out.println("currentHostAgentList: " + node.getSystemId()+", " + node.getServiceId() + ", " + node.getSerialId()));
                }

                String finalSystemId = systemId;
                agentListAll.forEach(node -> {
                    System.out.println("start:authQueue node systemId:" + node.getSystemId() + ", getServiceId: " + node.getServiceId()+ ", getSerialId: " + node.getSerialId());
                    PushHistory pushHistory = new PushHistory();
                    pushHistory.setSystemId(systemId);
                    pushHistory.setServiceId(node.getServiceId());
                    pushHistory.setSerialId(node.getSerialId());
                    pushHistory.setContent(JSONUtil.toJsonStr(changeObj));
                    pushHistory.setStatus(0);
                    pushHistroyService.insertPushHistroy(pushHistory);
                    System.out.println("start:authQueue node " + node.getSystemId() + "-" + node.getServiceId()+ "-" + node.getSerialId() + ", pushId: " + pushHistory.getId());
                    changeObj.putOpt("pushId", pushHistory.getId());
                    changeObj.putOpt("serviceId", node.getServiceId());
                    changeObj.putOpt("serialId", node.getSerialId());
                    String pushString = JSONUtil.toJsonStr(changeObj);
                    AgentIdentityDTO agentIdentityDTO = AgentIdentityDTO.builder().build();
                    agentIdentityDTO.setSystemId(finalSystemId);
                    agentIdentityDTO.setServiceId(node.getServiceId());
                    agentIdentityDTO.setSerialId(node.getSerialId());

                    if (currentHostAgentList.size() > 0) {
                        JSONArray currentHostAgentArray = JSONUtil.parseArray(JSONUtil.toJsonStr(currentHostAgentList));
                        JSONObject agentIdentityDTOObj = JSONUtil.parseObj(JSONUtil.toJsonStr(agentIdentityDTO));
                        boolean isExist = currentHostAgentArray.contains(agentIdentityDTOObj);
                        System.out.println("start:authQueue channel " + node.getSystemId() + "-" + node.getServiceId()+ "-" + node.getSerialId() + ", isExist: " + isExist);
                        if (isExist) {
                            incrementalCacheService.pushIncrementToClient(JSONUtil.parseObj(obj).get("systemId").toString(), node.getServiceId(), node.getSerialId(), pushString);
                            System.out.println("sytemId " + systemId + "serviceId " + node.getServiceId() + " serailId " + node.getServiceId() + " done");
                        }

                    }

                });
            }
            //System.out.println(1);
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("receive desensitizationQueue error" + obj);
        }
    }

    @Recover
    public void recover(Exception e, String obj) {
        System.out.println("回调方法执行！！！！" + obj);
        AgentNode agentNodeQuery = new AgentNode();
        String systemId = JSONUtil.parseObj(obj).get("systemId") == null ? JSONUtil.parseObj(obj).get("system_id").toString() : JSONUtil.parseObj(obj).get("systemId").toString();
        String pushkey = JSONUtil.parseObj(obj).get("pushKey").toString();
        agentNodeQuery.setSystemId(systemId);
        List<AgentNode> agentListAll = agentNodeService.selectAgentNode(agentNodeQuery);
        JSONObject changeObj = new JSONObject();
        changeObj.putOpt("systemId", systemId);
        changeObj.putOpt("pushKey", pushkey);
        if ("permissionChange".equals(pushkey)) {
            String beforeObj = JSONUtil.parseObj(obj).get("old").toString();
            String afterObj = JSONUtil.parseObj(obj).get("new").toString();
            JSONObject damObj = JSONUtil.parseObj(obj);
            //String systemId = String.valueOf(damObj.get("system_id"));

            // authDTO.setIamBaseUrl(authConfig.getIamBaseUrl());
            JSONArray beforeArray = JSONUtil.parseArray(beforeObj);
            JSONArray afterArray = JSONUtil.parseArray(afterObj);

            JSONObject diffObj = pushService.damDiff(beforeArray, afterArray, systemId, 1, pageSize);
            int curPage = 1;
            int pageTotal = diffObj.getInt("pageTotal");
            diffObj.putOpt("pushId", systemId);
            diffObj.putOpt("pushKey", pushkey);
            diffObj.putOpt("page", curPage);
            diffObj.putOpt("pageSize", pageSize);
            diffObj.putOpt("change", diffObj.get("change"));
            diffObj.putOpt("pageTotal", pageTotal);
            pushService.pushToNode(systemId, agentListAll, diffObj);
            while (curPage < diffObj.getInt("pageTotal")) {
                curPage++;
                diffObj = pushService.damDiff(new JSONArray(), diffObj.getJSONArray("nextArr"), systemId,curPage, pageSize);
                diffObj.putOpt("systemId", systemId);
                diffObj.putOpt("pushKey", pushkey);
                diffObj.putOpt("page", curPage);
                diffObj.putOpt("pageSize", pageSize);
                diffObj.putOpt("change", diffObj.get("change"));
                diffObj.putOpt("pageTotal", pageTotal);
                pushService.pushToNode(systemId, agentListAll, diffObj);

            }
        } else if ("groupUserChange".equals(pushkey)) {

            systemId = JSONUtil.parseObj(obj).get("systemId").toString();
            changeObj.putOpt("pushKey", pushkey);
            changeObj.putOpt("systemId", systemId);
            JSONObject userChangeObj = JSONUtil.parseObj(JSONUtil.parseObj(obj).get("change")).getJSONObject("userChange");
            String groupId = userChangeObj.getStr("groupId");
            String url = StrUtil.format(authConfig.getApiUrlForGetDamInfoByGroupId(), groupId);
            String json = HttpUtil.get(url);
            if (JSONUtil.isTypeJSONArray(JSONUtil.parseObj(json).get("data").toString())) {
                JSONArray groupUserChangeDamArr = JSONUtil.parseObj(json).getJSONArray("data");
                if (groupUserChangeDamArr != null) {
                    JSONObject diffObj = pushService.getGroupUserChangeDam(groupUserChangeDamArr, systemId,userChangeObj);
                    int curPage = 1;
                    diffObj.putOpt("pushKey", pushkey);
                    diffObj.putOpt("systemId", systemId);
                    diffObj.putOpt("page", curPage);
                    diffObj.putOpt("pageSize", pageSize);
                    //  diffObj.putOpt("change", diffObj.get("pushArr"));
                    diffObj.putOpt("pageTotal", diffObj.get("pageTotal"));
                    pushService.pushToNode(systemId, agentListAll, diffObj);

                }
            }
        } else if ("desensitizationChange".equals(pushkey)) {

            changeObj.putOpt("change", JSONUtil.parseObj(obj).get("change"));
            changeObj.putOpt("pushKey", pushkey);

            AgentNode agentNode = new AgentNode();
            agentNode.setSystemId(systemId);
            List<AgentIdentityDTO> currentHostAgentList = incrementalCacheService.getAgentIds(systemId);
            String finalSystemId = systemId;
            String finalSystemId4 = systemId;
            agentListAll.forEach(node -> {
                PushHistory pushHistory = new PushHistory();
                pushHistory.setSystemId(finalSystemId4);
                pushHistory.setServiceId(node.getServiceId());
                pushHistory.setSerialId(node.getSerialId());
                pushHistory.setContent(JSONUtil.toJsonStr(changeObj));
                pushHistory.setStatus(0);
                pushHistroyService.insertPushHistroy(pushHistory);
                changeObj.putOpt("pushId", pushHistory.getId());
                changeObj.putOpt("serviceId", node.getServiceId());
                changeObj.putOpt("serialId", node.getSerialId());
                String pushString = JSONUtil.toJsonStr(changeObj);
                AgentIdentityDTO agentIdentityDTO = AgentIdentityDTO.builder().build();
                agentIdentityDTO.setSystemId(finalSystemId);
                agentIdentityDTO.setServiceId(node.getServiceId());
                agentIdentityDTO.setSerialId(node.getSerialId());
                if (currentHostAgentList.size() > 0) {
                    JSONArray currentHostAgentArray = JSONUtil.parseArray(JSONUtil.toJsonStr(currentHostAgentList));
                    JSONObject agentIdentityDTOObj = JSONUtil.parseObj(JSONUtil.toJsonStr(agentIdentityDTO));
                    if (currentHostAgentArray.contains(agentIdentityDTOObj)) {
                        incrementalCacheService.pushIncrementToClient(JSONUtil.parseObj(obj).get("systemId").toString(), node.getServiceId(), node.getSerialId(), pushString);
                        System.out.println("sytemId " + finalSystemId4 + "serviceId " + node.getServiceId() + " serailId " + node.getServiceId() + " done");
                    }

                }

            });

            //记日志到数据库 或者调用其余的方法

        }
    }
}
